package com.onion.utils.utils;

import cn.hutool.core.date.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

public class FutureHelper {

    private static Logger logger = LoggerFactory.getLogger(FutureHelper.class);

    /**
     * 尝试获取Future结果
     * @param future
     * @param <V>
     * @return
     */
    public static <V> V tryAndGet(Future<V> future){
        if(future==null){
            return null;
        }
        if(future.isDone() || future.isCancelled()){
            try {
                return future.get();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
        }else{
            throw new RuntimeException("Future任务未完成，请稍等重试!");
        }
    }

    /**
     * 等待Future完成
     * @param futrueMap
     * @param timeout
     * @param <K>
     */
    public static <K> void waitForDone(Map<K, Future<?>> futrueMap, long timeout){
        if(futrueMap==null || futrueMap.isEmpty()){
            return;
        }
        waitForDone(futrueMap.values(), timeout);
    }

    /**
     * 等待Future完成
     * @param futures
     * @param timeout
     * @param <K>
     */
    public static <K> void waitForDone(Collection<Future<?>> futures, long timeout){
        long expired = System.currentTimeMillis() + timeout;

        Collection<Future<?>> futureList = new ArrayList<>(futures);
        Future<?> curFuture = null;
        while (true){
            Iterator<Future<?>> itor = futureList.iterator();
            while(itor.hasNext()){
                curFuture = (Future<?>) itor.next();
                if(curFuture.isDone() || curFuture.isCancelled()){
                    itor.remove();
                }else{
                    //Future超时->取消
                    if(System.currentTimeMillis() > expired){
                        if(curFuture.cancel(true) == false){
                            logger.warn("获取Future结果超时：取消失败，请检查原因!");
                        }
                        itor.remove();
                    }
                }
            }
            if(futureList.isEmpty()){
                return;
            }
            try {
                Thread.sleep(10L);
            } catch (InterruptedException exp) {
            }
        }
    }

    public static void main(String[] args){
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Map<Integer,Future<?>> futureMap = new HashMap<>();
        Date now = new Date();
        for(int i=0; i<10; i++){
            Future<Long> future = executorService.submit(new FutureTask());
            futureMap.put(i, future);
        }
        FutureHelper.waitForDone(futureMap, 10000L);
        futureMap.forEach((key, future)->{
            try {
                System.out.println(key+"....."+future.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });
        System.out.println(String.format("开始时间:%s, 结束时间:%s", DateUtil.format(now, "yyyy-MM-dd HH:mm:ss"),
                DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")));
    }

    static class FutureTask implements Callable<Long> {
        static AtomicLong count = new AtomicLong(0);
        @Override
        public Long call() throws Exception {
            Thread.sleep(10_000);
            long result = count.incrementAndGet();
            System.out.println("call....."+result);
            return result;
        }
    }

}